#ifndef UDPCOMMUNICATOR_H
#define UDPCOMMUNICATOR_H

#include <QObject>
#include <QUdpSocket>
#include <QHostAddress>
#include <QByteArray>
#include <QDataStream>
#include "ProtocolStructures.h" // 包含协议结构体定义

// 宏定义用于控制接收数据时的调试输出
#ifdef UDP_COMM_DEBUG_RECEIVE
#define UDP_RECEIVE_DEBUG(msg) qDebug() << "UdpCommunicator [Recv Debug]:" << msg
#else
#define UDP_RECEIVE_DEBUG(msg) Q_UNUSED(msg) // 生产环境禁用，避免警告
#endif

class UdpCommunicator : public QObject
{
    Q_OBJECT

public:
    explicit UdpCommunicator(QObject *parent = nullptr);
    ~UdpCommunicator();

    // 绑定本地端口
    bool bindLocalPort(quint16 port);

    // 设置目标地址和端口
    void setTargetAddress(const QHostAddress &address, quint16 port);
    void setTargetAddress(const QString &address, quint16 port);

    // 发送数据 (增加模板函数，方便直接发送结构体)
    template<typename T>
    void sendStructuredData(FunctionCode functionCode, const T& data);
    // 也可以保留通用的QByteArray发送函数
    void sendRawData(FunctionCode functionCode, const QByteArray &data); // 重命名以区分

    // 新增：设置是否启用接收调试信息打印
    void setReceiveDebugEnabled(bool enabled);

signals:
    // 接收到有效协议数据包的信号，增加发送方IP和端口
    void dataReceived(FunctionCode functionCode, const QByteArray &data,
                      const QHostAddress &senderAddress, quint16 senderPort);

    // 可以为特定结构体定义更具体的信号（可选，如果需要更强的类型检查）
    void heartbeatReceived(const HeartbeatPacket& packet, const QHostAddress &senderAddress, quint16 senderPort);
    void deviceInfoResponseReceived(const DeviceInfoResponsePacket& packet, const QHostAddress &senderAddress, quint16 senderPort);
    // ... 其他结构体信号

private slots:
    // 处理UDP套接字的可读数据
    void readPendingDatagrams();

private:
    QUdpSocket *m_udpSocket;
    QHostAddress m_targetAddress;
    quint16 m_targetPort;
    bool m_receiveDebugEnabled; // 控制接收调试打印的开关

    // 协议解析状态机
    enum ParseState {
        WaitingForHeader1,
        WaitingForHeader2,
        WaitingForFunctionCode,
        WaitingForDataLength1,
        WaitingForDataLength2,
        WaitingForData,
        WaitingForCrc1,
        WaitingForCrc2
    };

    ParseState m_parseState;
    QByteArray m_receiveBuffer;
    FunctionCode m_currentFunctionCode; // 使用枚举类型
    quint16 m_currentDataLength;
    QByteArray m_currentData;
    quint16 m_currentCrcReceived;
    QHostAddress m_currentSenderAddress; // 存储当前数据包的发送方地址
    quint16 m_currentSenderPort;       // 存储当前数据包的发送方端口

    // 计算CRC16
    quint16 calculateCrc16(const QByteArray &data);
    // 检查CRC16
    bool checkCrc16(const QByteArray &data, quint16 crc);
};

// 模板函数的实现必须放在头文件或类定义的后面
template<typename T>
void UdpCommunicator::sendStructuredData(FunctionCode functionCode, const T& data)
{
    QByteArray payload;
    QDataStream stream(&payload, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian); // 确保字节序一致

    // 将结构体数据直接写入QByteArray
    // 注意：这里假设T是一个POD类型或兼容QDataStream写入的类型
    // 对于自定义结构体，QDataStream不能直接序列化，需要手动写入每个成员
    // 为了简化，这里直接使用memcpy，这要求结构体是紧凑打包的 (#pragma pack(1))
    // 并且发送方和接收方的字节序一致。
    stream.writeRawData(reinterpret_cast<const char*>(&data), sizeof(T));

    sendRawData(functionCode, payload);
}

#endif // UDPCOMMUNICATOR_H
